package ejb.managerbeans;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJBContext;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;

import ejb.dto.PacchettoDTO;
import ejb.dto.ProdottoBaseDTO;
import ejb.entities.Basicproduct;
import ejb.entities.Group;
import ejb.entities.Pack;
import ejb.entities.User;
import ejb.entities.UserPack;
import ejb.utility.ConvertDTO;

/**
 * Session Bean implementation class PackManagerBean
 */
@Stateless
public class PackManagerBean implements PackManagerBeanLocal {

	@PersistenceContext
	private EntityManager em;

	@Resource
	EJBContext context;

	/**
	 * Default constructor.
	 */
	public PackManagerBean() {
	}

	public Basicproduct findPb(int id) {
		return em.find(Basicproduct.class, id);
	}

	public Pack find(int id) {
		return em.find(Pack.class, id);
	}

	@Override
	public void creaPacchetto(PacchettoDTO pDTO) {
		// creo nuovo paccehtto
		Pack p = new Pack(pDTO);
		User user = em.find(User.class, context.getCallerPrincipal().getName());
		user.getPacks().add(p);
		p.setUser(user);
		for (ProdottoBaseDTO pbDTO : pDTO.getProdottiBase()) {
			p.getBasicproducts().add(findPb(pbDTO.getId()));
		}
		for (ProdottoBaseDTO pbDTO : pDTO.getProdottiBase()) {
			Basicproduct oldpb = findPb(pbDTO.getId());
			Basicproduct editpb = em.merge(oldpb);
			editpb.getPacks().add(p);
		}
	}

	// non funziona
	@Override
	public void modificaPacchetto(PacchettoDTO pDTO) {
		// modifica paccehtto
		Pack pold = find(pDTO.getId());
		Pack pnew = em.merge(pold);
		pnew.setDescription(pDTO.getDescrizione());
		pnew.setDiscount(pDTO.getSconto());
		pnew.setEnddate(pDTO.getDataFine());
		pnew.setName(pDTO.getNome());
		pnew.setStartdate(pDTO.getDataInizio());
		pnew.setPrice(pDTO.getPrezzo());

		// se l'utente che sta modificando  diverso lo salvo altrimenti
		// mantengo lo stesso
		User uold = pold.getUser();
		User unew = em.find(User.class, context.getCallerPrincipal().getName());
		if (!uold.getUserid().equals(unew.getUserid())) {
			uold = em.merge(pold.getUser());
			uold.removePack(pold);
			unew.addPack(pnew);
			pnew.setUser(unew);
		}

		// lista prodotti base vecchi
		List<Basicproduct> listOldBp = new ArrayList<Basicproduct>();
		listOldBp = pold.getBasicproducts();
		// pulisco la lista dei prodotti base nel nuovo pacchetto
		pnew.getBasicproducts().clear();
		// aggiungo i nuovi prodotti base al pacchetto
		for (ProdottoBaseDTO pbDTO : pDTO.getProdottiBase()) {
			pnew.getBasicproducts().add(findPb(pbDTO.getId()));
		}

		// la scorro e elimino dai prodotti base nella lista il pacchetto
		// modificato
		for (Basicproduct b : listOldBp) {
			b.getPacks().remove(pold);
		}

		// aggiungo il pacchetto modificato ai nuovi prodotti base
		for (ProdottoBaseDTO pbDTO : pDTO.getProdottiBase()) {
			Basicproduct oldpb = findPb(pbDTO.getId());
			Basicproduct editpb = em.merge(oldpb);
			editpb.getPacks().add(pnew);
		}
	}

	@Override
	public void aggiornaPacchetto(PacchettoDTO pDTO) {
		Pack pack = (Pack) em.find(Pack.class, pDTO.getId());

		if (pack != null) {
			Pack pack2 = em.merge(pack);
			aggiornaValori(pack2, pDTO);
		} else
			System.out.println("Pacchetto non trovato nel db");
	}

	private void aggiornaValori(Pack packDaAggiornare, PacchettoDTO pDTO) {
		List<Basicproduct> bProducts = new ArrayList<Basicproduct>();

		for (ProdottoBaseDTO pb : pDTO.getProdottiBase())
			bProducts
					.add((Basicproduct) em.find(Basicproduct.class, pb.getId()));

		// aggiorno tutti i campi
		packDaAggiornare.setBasicproducts(bProducts);
		packDaAggiornare.setDescription(pDTO.getDescrizione());
		packDaAggiornare.setDiscount(pDTO.getSconto());
		packDaAggiornare.setEnddate(pDTO.getDataFine());
		packDaAggiornare.setName(pDTO.getNome());
		packDaAggiornare.setPrice(pDTO.getPrezzo());
		packDaAggiornare.setStartdate(pDTO.getDataInizio());
	}

	@Override
	public List<PacchettoDTO> getAllPacks() {
		List<Pack> ps = em.createNamedQuery(Pack.FINDALL, Pack.class)
				.getResultList();
		List<PacchettoDTO> pDtos = new ArrayList<PacchettoDTO>();

		for (Pack p : ps)
			pDtos.add(ConvertDTO.convertToDTOPack(p));

		return pDtos;

	}

	@Override
	public void eliminaPacchetto(int idPacchettoDaEliminare) 
	{
		Pack p = new Pack();
		User user = new User();

		try {
			// estrae dal db il pacchetto e chi l'ha creato
			p = (Pack) em.createNamedQuery(Pack.FIND_BYID, Pack.class)
					.setParameter("idPack", idPacchettoDaEliminare)
					.getSingleResult();
			user = (User) em.createNamedQuery(User.FINDBYID, User.class)
					.setParameter("id", p.getUser().getUserid())
					.getSingleResult();
		} catch (NoResultException e) 
		{
		}

		List<Basicproduct> bpInPack = new ArrayList<Basicproduct>();
		bpInPack = p.getBasicproducts();
		for (Basicproduct b : bpInPack) {
			b.getPacks().remove(p);
		}
		// elimino il pacchetto dalla lista dei pacchetti creati dall'utente
		if (user.getPacks().contains(p))
			user.getPacks().remove(p);
		em.remove(p);
	}

	@Override
	public PacchettoDTO getPackDTOPerId(int idPacchetto) {
		return ConvertDTO.convertToDTOPack((Pack) em.find(Pack.class,
				idPacchetto));
	}

	@Override
	@RolesAllowed({ Group.ADMIN })
	public List<PacchettoDTO> getAllPacksMadeByAdmins() {
		List<PacchettoDTO> pacchettoDTOs = new ArrayList<PacchettoDTO>();

		// lista di tutti i pacchetti nel db
		List<Pack> packs = em.createNamedQuery(Pack.FINDALL, Pack.class)
				.getResultList();

		// lista temporanea per inserire tutti i pacchetti creati da admin
		List<Pack> tempPacks = new ArrayList<Pack>();

		// group per il controllo se pack creato da admin o no
		Group admin = em.find(Group.class, "ADMINS");

		// riempio la lista temPacks
		for (Pack p : packs) {
			if (p.getUser().getGroups().contains(admin)) {
				tempPacks.add(p);
			}
		}

		// converto lista in lista di pacchettiDTO
		for (Pack p : tempPacks) {
			pacchettoDTOs.add(ConvertDTO.convertToDTOPack(p));
		}

		return pacchettoDTOs;
	}

	@Override
	@RolesAllowed({ Group.USER })
	public List<PacchettoDTO> getAllPacksOfUserLogged() {
		List<PacchettoDTO> pacchettoDTOs = new ArrayList<PacchettoDTO>();

		// UserManagerBean um = new UserManagerBean();
		try {
			// estraggo lista pacchetti creati dall'utente
			List<Pack> packs = em
					.createNamedQuery(Pack.FINDPACKCREATEDBYUSER, Pack.class)
					.setParameter("userid",
							context.getCallerPrincipal().getName())
					.getResultList();

			// converto lista di pack in pacchetti dto
			for (Pack p : packs)
				pacchettoDTOs.add(ConvertDTO.convertToDTOPack(p));
		} catch (Exception e) {
		}
		return pacchettoDTOs;
	}

	@Override
	public List<PacchettoDTO> getPackDTOPerDate(PacchettoDTO pacchetto) {

		List<PacchettoDTO> pacchettiDTO = new ArrayList<PacchettoDTO>();

		List<Pack> packs = em.createNamedQuery(Pack.FIND_DATES, Pack.class)
				.setParameter("dataInizio", pacchetto.getDataInizio())
				.setParameter("dataFine", pacchetto.getDataFine())
				.getResultList();
		;

		for (Pack p : packs) {
			pacchettiDTO.add(ConvertDTO.convertToDTOPack(p));

		}
		return pacchettiDTO;

	}

	public void boughtPack(PacchettoDTO p) {

		// Aggiungi il pacchetto acquistato alla lista dei pacchetti
		// acquistati dall'utente
		Pack pack = em.find(Pack.class, p.getId());

		User user = em.find(User.class, context.getCallerPrincipal().getName());

		user.getPacks().add(pack);

		UserPack newUP = new UserPack();

		newUP.setDate(new Date());
		newUP.setPack(pack);
		newUP.setUser(user);

		// Associa al prodottobase la relazione con l'utente
		pack.getUserPacks().add(newUP);

		em.persist(newUP);

		System.out.println("inserito in user_pack:"
				+ newUP.getUser().getUserid().toString());

	}

}
